package com.qwc.blog.entity.vo.resource;

import cn.hutool.core.collection.CollUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.qwc.blog.entity.Resource;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import static com.qwc.blog.common.constant.CommonConstant.*;

/**
 * @author qwc
 * @Date 2021/10/23 18:45
 */
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class RouterVo {
    /**
     * 路由名字
     */
    private String name;

    /**
     * 路由地址
     */
    private String path;

    /**
     * 是否隐藏路由，当设置 true 的时候该路由不会再侧边栏出现
     */
    private boolean hidden;

    /**
     * 重定向地址，当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
     */
    private String redirect;

    /**
     * 组件地址
     */
    private String component;

    /**
     * 当你一个路由下面的 children 声明的路由大于1个时，自动会变成嵌套的模式--如组件页面
     */
    private Boolean alwaysShow;

    /**
     * 其他元素
     */
    private MetaVo meta;

    /**
     * 子路由
     */
    private List<RouterVo> children;

    /**
     * 获取树结构的路由vo
     *
     * @param resList
     * @return
     */
    public static List<RouterVo> getTreeRouter(List<Resource> resList) {
//        获取所有资源resId
        List<Long> resId = resList.stream().map(Resource::getResId).collect(Collectors.toList());
        List<RouterVo> routerVoList = new LinkedList<>();
        for (Iterator<Resource> iterator = resList.iterator(); iterator.hasNext(); ) {
            Resource resource = iterator.next();
//            pid为0是顶级资源，resId没有为0的资源，pid不在resId内的是顶级资源
            if (!resId.contains(resource.getPid())) {
//                获取最顶级资源，递归获取它们的子资源
                RouterVo treeList = getRouterChildren(resource, resList);
                routerVoList.add(treeList);
            }
        }
        return routerVoList;
    }

    /**
     * 递归生成树结构资源
     *
     * @param resource
     * @param resList
     * @return
     */
    private static RouterVo getRouterChildren(Resource resource, List<Resource> resList) {
//        设置父资源信息
        RouterVo routerVo = new RouterVo();
        routerVo.setHidden(NO.equals(resource.getVisible()));
        routerVo.setName(getRouteName(resource));
        routerVo.setPath(getPath(resource));
        routerVo.setComponent(getComponent(resource));
//        设置父资源meta
        routerVo.setMeta(new MetaVo(resource.getResName(), resource.getIcon(), NO_INT.equals(resource.getIsCache()), resource.getPath()));
//        获取子资源
        List<Resource> children = resList.stream()
                .filter(res -> res.getPid().equals(resource.getResId()))
                .collect(Collectors.toList());
//        判断父资源类型：目录，一级菜单，一级链接，菜单，目录里的链接
//        第一种：目录，
        if (isDirectory(resource, children)) {
            routerVo.setAlwaysShow(true);
            routerVo.setRedirect("noRedirect");
            routerVo.setChildren(children.stream()
                    .map(res -> getRouterChildren(res, resList))
                    .collect(Collectors.toList()));
//        第二种：一级目录，没有meta和children，但要设置一个子routerVo
        } else if (isFirstMenuNotFrame(resource)) {
            routerVo.setMeta(null);
            RouterVo child = new RouterVo();
            child.setPath(resource.getPath());
            child.setComponent(resource.getComponent());
            child.setName(StringUtils.capitalize(resource.getPath()));
            child.setMeta(new MetaVo(resource.getResName(), resource.getIcon(), NO_INT.equals(resource.getIsCache()), resource.getPath()));
            routerVo.setChildren(Arrays.asList(child));
//         第三种：一级链接
        } else if (isFirstFrame(resource)) {
            routerVo.setMeta(new MetaVo(resource.getResName(), resource.getIcon()));
            routerVo.setPath(INNER);
            RouterVo child = new RouterVo();
            String routerPath = StringUtils.replaceEach(resource.getPath(), new String[]{HTTP, HTTPS}, new String[]{"", ""});
            child.setPath(routerPath);
            child.setComponent(INNER_LINK);
            child.setName(StringUtils.capitalize(routerPath));
            child.setMeta(new MetaVo(resource.getResName(), resource.getIcon(), resource.getPath()));
            routerVo.setChildren(Arrays.asList(child));
        }
        return routerVo;
    }

    /**
     * 获取routeName
     *
     * @param resource
     * @return
     */
    private static String getRouteName(Resource resource) {
        String routerName = StringUtils.capitalize(resource.getPath());
        // 如果是一级菜单，没有routeName
        if (isFirstMenuNotFrame(resource)) {
            routerName = StringUtils.EMPTY;
        }
        return routerName;
    }

    /**
     * 判断一级资源是不是菜单
     *
     * @param resource
     * @return
     */
    private static boolean isFirstMenuNotFrame(Resource resource) {
        return TOP_PARENT.equals(resource.getPid()) && TYPE_MENU.equals(resource.getResType())
                && NO_INT.equals(resource.getIsFrame());
    }

    /**
     * 组件
     *
     * @param resource
     * @return
     */
    private static String getComponent(Resource resource) {
        String component = LAYOUT;
        if (StringUtils.isNotEmpty(resource.getComponent()) && !isFirstMenuNotFrame(resource)) {
            component = resource.getComponent();
        } else if (StringUtils.isEmpty(resource.getComponent())
                && !TOP_PARENT.equals(resource.getPid())
                && isInnerLink(resource)) {
            component = INNER_LINK;
        } else if (StringUtils.isEmpty(resource.getComponent())
                && isParentView(resource)) {
            component = PARENT_VIEW;
        }
        return component;
    }

    /**
     * 路径
     *
     * @param resource
     * @return
     */
    private static String getPath(Resource resource) {
        String routerPath = resource.getPath();
//        不是一级资源，不是外链，内链打开外网
        if (!TOP_PARENT.equals(resource.getPid())
                && NO_INT.equals(resource.getIsFrame())
                && StringUtils.startsWithAny(resource.getPath(), HTTP, HTTPS)) {
            routerPath = StringUtils.replaceEach(routerPath, new String[]{HTTP, HTTPS}, new String[]{"", ""});
        }
        if (TOP_PARENT.equals(resource.getPid())
                && NO_INT.equals(resource.getIsFrame())
                && TYPE_DIR.equals(resource.getResType())) {
//            一级目录
            routerPath = DELIMITER + resource.getPath();
        } else if (isFirstMenuNotFrame(resource)) {
//            一级菜单
            routerPath = DELIMITER;
        }
        return routerPath;
    }

    private static boolean isFirstFrame(Resource resource) {
        return TOP_PARENT.equals(resource.getPid())
                && isInnerLink(resource);
    }

    /**
     * 资源是目录，且目录下有子资源
     *
     * @param resource
     * @param children
     * @return
     */
    private static boolean isDirectory(Resource resource, List<Resource> children) {
        return CollUtil.isNotEmpty(children)
                && TYPE_DIR.equals(resource.getResType());
    }

    /**
     * 是否内链组件
     *
     * @param resource
     * @return
     */
    private static boolean isInnerLink(Resource resource) {
        return NO_INT.equals(resource.getIsFrame())
                && StringUtils.startsWithAny(resource.getPath(), HTTP, HTTPS);
    }

    /**
     * 是否非一级目录
     *
     * @param resource
     * @return
     */
    private static boolean isParentView(Resource resource) {
        return !TOP_PARENT.equals(resource.getPid()) && TYPE_DIR.equals(resource.getResType());
    }
}
